package com.king.freefish.common.web.handle;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjUtil;
import com.king.freefish.common.annotation.SensitiveData;
import com.king.freefish.common.annotation.SensitiveField;
import com.king.freefish.common.annotation.SensitiveMethod;
import com.king.freefish.common.enums.SensitiveType;
import com.king.freefish.common.util.R;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @packageName com.king.freefish.common.web.handle
 * @author: jinguoguang
 * @date: 2025/7/29 15:59
 * @description: 全局响应
 **/
@ControllerAdvice
public class GlobalResponseBodyHandler implements ResponseBodyAdvice<Object> {
    /**
     * 缓存敏感字段信息 避免重复反射
     */
    private static final ClassValue<List<Field>> SENSITIVE_FIELDS_CACHE = new ClassValue<List<Field>>() {
        @Override
        protected List<Field> computeValue(Class<?> type) {
            return Arrays.stream(type.getDeclaredFields())
                    .filter(f -> f.isAnnotationPresent(SensitiveField.class))
                    .collect(Collectors.toList());
        }
    };
    /**
     * 缓存敏感类型信息 避免重复
     */
    private static final ClassValue<List<Field>> SENSITIVE_TYPE_CACHE = new ClassValue<List<Field>>() {
        @Override
        protected List<Field> computeValue(Class<?> type) {
            return Arrays.stream(type.getDeclaredFields())
                    .filter(f -> f.isAnnotationPresent(SensitiveData.class))
                    .collect(Collectors.toList());
        }
    };

    /**
     * 判断是否支持
     *
     * @param returnType    the return type
     * @param converterType the selected converter type
     * @return true则拦截执行 false则跳过
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 判断是否包含SensitiveData注解 数据脱敏
        return returnType.hasMethodAnnotation(SensitiveMethod.class);
    }

    /**
     * 在响应之前拦截
     *
     * @param body                  the body to be written
     * @param returnType            the return type of the controller method
     * @param selectedContentType   the content type selected through content negotiation
     * @param selectedConverterType the converter type selected to write to the response
     * @param request               the current request
     * @param response              the current response
     * @return 修改后的响应体
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 非空处理
        if (ObjUtil.isNull(body)) {
            return body;
        }
        // 脱敏处理
        processResult(body);
        return body;
    }

    /**
     * 处理结果
     *
     * @param body 响应体
     */
    private void processResult(Object body) {
        if (!(body instanceof R)) {
            return;
        }
        // 获取结果数据
        Object data = ((R<?>) body).getData();
        // 非空校验
        if (ObjUtil.isNull(data)) {
            return;
        }
        // //处理分页数据
        // if (data instanceof IPage) {
        //     //处理分页数据
        //     processSensitiveData(((IPage<?>) data).getRecords());
        // }
        // 处理非分页数据
        processSensitiveData(data);
    }


    /**
     * 处理敏感数据
     *
     * @param body 响应体
     */
    private void processSensitiveData(Object body) {
        // 处理集合类型
        if (body instanceof Collection) {
            ((Collection<?>) body)
                    .forEach(this::processSensitiveData);
            return;
        }
        // 处理数组类型
        if (body.getClass().isArray()) {
            Arrays.stream((Object[]) body)
                    .forEach(this::processSensitiveData);
            return;
        }
        // 处理对象类型
        maskObject(body);
    }


    /**
     * 处理脱敏
     *
     * @param obj 对象
     */
    private void maskObject(Object obj) {
        List<Field> typeFields = SENSITIVE_TYPE_CACHE.get(obj.getClass());
        // 非空校验
        if (CollUtil.isNotEmpty(typeFields)) {
            // 遍历
            typeFields.forEach(this::maskObject);
        }
        // 获取当前对象所有字段
        List<Field> fields = SENSITIVE_FIELDS_CACHE.get(obj.getClass());
        // 非空校验
        if (CollUtil.isEmpty(fields)) {
            return;
        }
        // 遍历字段
        fields.forEach(field -> {
            try {
                // 设置字段可访问
                field.setAccessible(true);
                // 获取字段值
                Object value = field.get(obj);
                // 非空校验
                if (value == null) {
                    return;
                }
                // 递归处理嵌套对象/集合
                processSensitiveData(value);
                // 应用脱敏规则
                if (field.isAnnotationPresent(SensitiveField.class)) {
                    SensitiveType type = field.getAnnotation(SensitiveField.class).value();
                    value = maskObject(value, type);
                }
                // 设置处理后的值
                field.set(obj, value);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("脱敏字段访问失败: " + field.getName(), e);
            }
        });
    }


    /**
     * 脱敏对象
     *
     * @param obj  对象
     * @param type 类型
     * @return 脱敏后的对象
     */
    private Object maskObject(Object obj, SensitiveType type) {
        // 非空校验
        if (ObjUtil.isNull(obj)) {
            return obj;
        }
        // 仅处理字符串
        if (!(obj instanceof String)) {
            return obj;
        }
        switch (type) {
            case NAME:
                return DesensitizedUtil.chineseName((String) obj);
            case ID_CARD:
                return DesensitizedUtil.idCardNum((String) obj, 4, 4);
            case LANDLINE:
                return DesensitizedUtil.fixedPhone((String) obj);
            case PHONE:
                return DesensitizedUtil.mobilePhone((String) obj);
            case ADDRESS:
                return DesensitizedUtil.address((String) obj, 6);
            case EMAIL:
                return DesensitizedUtil.email((String) obj);
            case BANK_CARD:
                return DesensitizedUtil.bankCard((String) obj);
            case PASSWORD:
                return DesensitizedUtil.password((String) obj);
            default:
                return DesensitizedUtil.firstMask((String) obj);
        }
    }
}
